#!/usr/bin/perl

use warnings;
use strict;

################################################################
## This file is to parse the vector file to Piecewise Linear(PWL)
##   format for spectre stimuli.
##
## The vector file must meet the required format. Please refer to
##   to the example vector file 'stimuli.vec'.
##
## Written for ECE432/ECE632 class, Nov. 27, 2007
##
## Modifed by Kyle Craig & Joe Ryan June 2009
## New Version will read in ModelSim saved tabular lists
## Add list file as the second arguement passed in the command line
## i.e, perl vec2pwl_kc2_modified.pl stimuli.vec list.lst stimuli.scs
################################################################

my $infile = $ARGV[0];
my $infile2 = $ARGV[1];
my $outfile = $ARGV[2];

# Open files
open(IN, "$infile") || die("Could not open file!");
open(OUT, ">$outfile") || die("Could not open file!");

my $HoH;
my $replace = "/tb_brightness/";
my $vih;
my $vil;
my $trise;
my $tfall;
my $tunit;
my @bitNum;
my $wave2;

my @namelist = namelister($infile2,$replace);
print "@namelist\n";
open(IN2, $infile2) || die("Could not open file!");
# Parse the vector header
while (my $line = <IN> ) {
    chomp($line);
    my @cols = split(/\s+/, $line);
    
    if ($line =~ /^radix/) {
	@bitNum = @cols; 

    }

    elsif ($line =~ /^tunit/) {
	if ($cols[1] eq 's') {
	    $tunit = "";
	} else {
	    $tunit = substr($cols[1], 0, 1);
	}
    }
    elsif ($line =~ /^trise/) {
	$trise = $cols[1];
    }
    elsif ($line =~ /^tfall/) {
	$tfall = $cols[1];
    }
    elsif ($line =~ /^vih/) {
	$vih = $cols[1];
    }
    elsif ($line =~ /^vil/) {
	$vil = $cols[1];
    }

    elsif ($line =~ /^vname/) {
	my @vname = @namelist;

	for (my $i=0; $i<$#vname+1; $i++) {
    
$HoH->{$vname[$i]}->{'bits'} = $bitNum[$i+1];
}



while (my $line = <IN2>) {
    $line = stripper($line,$replace);
    @cols = split(/\s+/, $line);

    if ($line =~ /^\d/) {

	for (my $i=0; $i<$#cols; $i++) {

 $HoH->{$vname[$i]}->{$cols[0]} = $cols[$i+1];

}
}
}
}
}

print OUT "VSS VSS 0 0 \n";
print OUT "VDD VDD 0 1.2\n";

# Parse each bit to the Piecewise Linear (PWL) format
for my $wave (keys %$HoH) {
    my $bits = $HoH->{$wave}->{'bits'};

    my $value;
    my $prev;
    my $t0;
    my $t;
    delete $HoH->{$wave}->{'bits'};
    if ($bits==1) {
		$wave2 = uc($wave); #send wave to uppercase...do not want here
	print OUT "V$wave $wave 0 pwl (";
        for $t (sort {$a<=>$b} keys %{$HoH->{$wave}}) {
	    my $v = $HoH->{$wave}->{$t};
	    # Parse to PWL format for spectre
	    if ($v==1) {
		$value=$vih;
	    } else {
		$value=$vil;
	    }  	  
	    if ($t==0) {
		print OUT "$t$tunit $value ";
	    } elsif ($value!=$prev) {
		if ($value==$vih) {
		   $t0=$t-$trise;
		} else {
		   $t0=$t-$tfall;
		} 
		print OUT "$t0$tunit $prev $t$tunit $value ";
	    }
	    $prev = $value;   
        }
        print OUT ")\n";
    }
    else {
 	# Parse each bit of the bus vector
        for (my $i=0; $i<$bits; $i++) {
		$wave2 = uc($wave);
	    print OUT "v$wave\_$i $wave\_$i 0 pwl(";
	    for $t (sort {$a<=>$b} keys %{$HoH->{$wave}}) {
	        my $vs = $HoH->{$wave}->{$t};

		if ($bits!=length($vs)) {
		    print "ERROR: The size of the vector for $wave at time $t is not equal to its radix!\n";
		    return;
		}
		my $v = substr($vs, $bits-1-$i, 1);
		# Parse to Piecewise Linear (PWL) Vector for spectre
		if ($v==1) {
		    $value=$vih;
		} else {
		    $value=$vil;
		}  	  
		if ($t==0) {
		    print OUT "$t$tunit $value ";
		} elsif ($value!=$prev) {
		    if ($value==$vih) {
		       $t0=$t-$trise;
		    } else {
		       $t0=$t-$tfall;
		    } 
		    print OUT "$t0$tunit $prev $t$tunit $value ";
		}
		$prev = $value;   
	    }
	    print OUT ")\n";
       }
    }
}

# Close files
close($infile);
close($infile2);
close($outfile);


sub namelister {
    my ($filename,$replace) = @_;

    open(FILE, $filename) || die("Could not open file!");

    my @templist;

    while (my $line = <FILE>) {

        $line = stripper($line,$replace);
        last if $line =~ /^\d/;

        my @cols = split(/\s+/, $line);
        push @templist, \@cols;
    }

    my @namelist;
    foreach  my $i (0 .. $#{$templist[0]}) {
        foreach my $j (0 .. $#templist) {
            next unless defined $templist[$j][$i];
            push @namelist, $templist[$j][$i];
        }
    }

    return @namelist;
}

sub stripper {
    my ($line,$replace) = @_;

    chomp($line);


   $line =~ s/$replace//g;
  $line =~ s/^\s*//; 
   $line =~ s/^ns +//; 
$line =~ s/^ps +//; 

##print "$line\n";
    return $line;
}
